package com.uvstu.common.upay;

import com.uvstu.common.exception.TClientException;
import org.apache.commons.codec.binary.Base64;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.UUID;

/**
 * @version V1.0
 * @Title: 加解密工具类
 * @author: zhengweibin
 * @Description:
 * @create: 2022-12-02 21:52
 */
public class EncryptionUtil {

    //AES算法 秘钥
    private static String encryptKey = "e470e204e8bb4318";

    /**
     * 获取 uuid
     *
     * @return
     */
    public static String getUuid() {
        String uuid = UUID.randomUUID().toString();
        return uuid;
    }

    /**
     * 设置 AES 加密秘钥
     *
     * @param key
     */
    public static void setAESConfig(String key) {
        encryptKey = key;
    }

    /**
     * AES算法 加密
     *
     * @param content
     * @return
     */
    public static String AESencrypt(String content) throws TClientException {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            kgen.init(128);
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));
            byte[] b = cipher.doFinal(content.getBytes("utf-8"));
            return Base64.encodeBase64String(b);
        } catch (Exception e) {
            throw new TClientException("加密失败！");
        }
    }

    /**
     * AES算法 解密
     *
     * @param content
     * @return
     */
    public static String AESdecrypt(String content) throws TClientException {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            kgen.init(128);
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));
            byte[] encryptBytes = Base64.decodeBase64(content);
            byte[] decryptBytes = cipher.doFinal(encryptBytes);
            return new String(decryptBytes);
        } catch (Exception e) {
            throw new TClientException("解密失败！");
        }
    }

    /**
     * BASE64 加密
     *
     * @param content
     * @return
     */
    public static String BASE64encrypt(String content) throws TClientException {
        try {
            BASE64Encoder encoder = new BASE64Encoder();
            String cipherText = encoder.encode(content.getBytes());
            return cipherText;
        } catch (Exception e) {
            throw new TClientException("加密失败！");
        }
    }

    /**
     * BASE64 解密
     *
     * @param content
     * @return
     */
    public static String BASE64decrypt(String content) throws TClientException {
        try {
            BASE64Decoder decoder = new BASE64Decoder();
            String plainText = new String(decoder.decodeBuffer(content));
            return plainText;
        } catch (Exception e) {
            throw new TClientException("解密失败！");
        }
    }


    /**
     * MD5加密
     *
     * @param content 要进行加密的文本
     * @param len     16/32 位加密数据
     * @return 加密后的内容
     */
    public static String textToMD5L32(String content, Integer len) throws TClientException {
        String result = null;
        //首先判断是否为空
        if (StringUtil.isNull(content)) {
            throw new TClientException("加密内容不能为空！");
        }
        if (len != 32 && len != 16) {
            throw new TClientException("加密长度只允许16位和32位！");
        }
        try {
            //首先进行实例化和初始化
            MessageDigest md = MessageDigest.getInstance("MD5");
            //得到一个操作系统默认的字节编码格式的字节数组
            byte[] btInput = content.getBytes();
            //对得到的字节数组进行处理
            md.update(btInput);
            //进行哈希计算并返回结果
            byte[] btResult = md.digest();
            //进行哈希计算后得到的数据的长度
            StringBuffer sb = new StringBuffer();
            for (byte b : btResult) {
                int bt = b & 0xff;
                if (bt < 16) {
                    sb.append(0);
                }
                sb.append(Integer.toHexString(bt));
            }
            if (len == 16) {
                result = sb.toString().substring(8, 24);
            } else if (len == 32) {
                result = sb.toString();
            }
            return result;
        } catch (NoSuchAlgorithmException e) {
            throw new TClientException("加密失败！");
        }
    }

    /**
     * 创建RSA公私钥对
     *
     * @return new RsaKeyPair(publicKeyString, privateKeyString)
     * @throws NoSuchAlgorithmException
     */
    public static RsaKeyPair generateKeyPair() throws NoSuchAlgorithmException {
        // 创建公私钥对，指定算法 - RSA
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        // 设置密钥大小 1024 bits， >=512
        keyPairGenerator.initialize(1024);
        // 创建KeyPair对象，用于接收公私钥对
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        // 生成随机的公私钥对
        RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
        // 把密钥转换成 Base64编码的字符串
        String publicKeyString = Base64.encodeBase64String(rsaPublicKey.getEncoded());
        String privateKeyString = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
        return new RsaKeyPair(publicKeyString, privateKeyString);
    }

    /**
     * 公钥加密方法
     *
     * @param publicKeyText 公钥
     * @param text          将要加密的信息
     * @return Base64编码的字符串
     * @throws Exception
     */
    public static String encryptByPublicKey(String publicKeyText, String text) throws TClientException {
        try {
            // 返回按照 X.509 标准进行编码的密钥的字节
            // x509EncodedKeySpec2 是一种规范、规格
            X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            // 让密钥工厂按照指定的 规范 生成公钥
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2);
            Cipher cipher = Cipher.getInstance("RSA");
            // 对加密初始化，使用加密模式，公钥加密
            // Cipher.ENCRYPT_MODE 可以用 1 代替
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);

            byte[] result = cipher.doFinal(text.getBytes());
            // 返回 Base64编码的字符串
            return Base64.encodeBase64String(result);
        } catch (Exception e) {
            throw new TClientException("加密失败：" + e.getMessage());
        }
    }

    /**
     * 公钥解密方法
     *
     * @param publicKeyText 公钥
     * @param text          待解密的信息
     * @return 字符串
     * @throws Exception
     */
    public static String decryptByPublicKey(String publicKeyText, String text) throws TClientException {
        try {
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            byte[] result = cipher.doFinal(Base64.decodeBase64(text));
            return new String(result);
        } catch (Exception e) {
            throw new TClientException("解密失败：" + e.getMessage());
        }
    }

    /**
     * 私钥加密方法
     *
     * @param privateKeyText 私钥
     * @param text           将要加密的信息
     * @return Base64编码的字符串
     * @throws Exception
     */
    public static String encryptByPrivateKey(String privateKeyText, String text) throws Exception {
        try {
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            byte[] result = cipher.doFinal(text.getBytes());
            return Base64.encodeBase64String(result);
        } catch (Exception e) {
            throw new TClientException("加密失败：" + e.getMessage());
        }
    }

    /**
     * 私钥解密方法
     *
     * @param privateKeyText 私钥
     * @param text           待解密的信息
     * @return 字符串
     * @throws Exception
     */
    public static String decryptByPrivateKey(String privateKeyText, String text) throws Exception {
        try {
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] result = cipher.doFinal(Base64.decodeBase64(text));
            return new String(result);
        } catch (Exception e) {
            throw new TClientException("解密失败：" + e.getMessage());
        }
    }

    /**
     * RSA密钥对 对象
     */
    public static class RsaKeyPair {
        private final String publicKey;
        private final String privateKey;

        public RsaKeyPair(String publicKey, String privateKey) {
            this.publicKey = publicKey;
            this.privateKey = privateKey;
        }

        public String getPublicKey() {
            return publicKey;
        }

        public String getPrivateKey() {
            return privateKey;
        }
    }

}
